home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
3D Class Library
/
main.cp
< prev
next >
Wrap
Text File
|
1996-06-27
|
9KB
|
383 lines
// =======================================================================
// 3D Class Library, © Xilex Group
// - ------------------------------------------------------------------- -
// Written by Dmitry Boldyrev
// =======================================================================
#include <stdio.h>
#include <string.h>
#include <QDOffscreen.h>
#include <profiler.h>
#include "3dcl.h"
Point middle;
Ptr baseAddr;
short rowBytes;
UBYTE *thepic;
typedef struct
{
unsigned char r:8, g:8, b:8;
} color;
color *pal;
Rect rBounds;
#define iHandCursor 200
#define iNewHandCursor 201
static void InitToolBox()
{
EventRecord event;
short count;
InitGraf((Ptr) &qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(0L);
InitCursor();
SetEventMask(everyEvent);
for (count = 1; count <= 3; count++) {
MoreMasters();
EventAvail(everyEvent, &event);
}
FlushEvents(everyEvent, 0);
}
static void load_pic (void)
{
FILE *fp;
thepic = new UBYTE[65535];
pal = new color[256];
fp = fopen ("o021.raw", "rb");
fread (pal, 1, sizeof(color) * 256, fp); /* Load the palette */
fread (thepic, 1, 65535, fp); /* Load the picture */
fclose (fp);
}
static void delete_pic (void)
{
delete[] pal;
delete[] thepic;
}
#define kDiffuse 24
#define kSpecular (32 - kDiffuse)
#define MAXCOL 64
static unsigned char closest_match (int red, int green, int blue, color *pal)
{
int colnum; /* Color number to compare */
int delta_r, delta_g, delta_b; /* Difference between new and existing */
float distance; /* Distance from new color */
float lowest_distance; /* Lowest distance found */
int closest_color; /* Color with the lowest distance */
lowest_distance = 33333;
/* Set to a high number, higher than anything possible.
The highest distance we can have is sqrt (64*64 + 64*64 + 64*64)
which is 110.85 */
for (colnum = 0; colnum < MAXCOL; colnum++)
/* Compare each color from the existing palette */
{
delta_r = (pal[colnum].r - red);
delta_g = (pal[colnum].g - green);
delta_b = (pal[colnum].b - blue);
distance = sqrt (delta_r*delta_r*30 + delta_g*delta_g*59 + delta_b*delta_b*11);
if (distance < lowest_distance)
{
lowest_distance = distance;
closest_color = colnum;
}
}
return (closest_color);
}
static void create_fade_table (int frame, int maxframe,
unsigned char *fadetable, color *pal)
{
float lightlevel1; /* Percentage of color 1 */
float lightlevel2; /* Percentage of color 2 */
float fr, fg, fb; /* Floating point RGB values of color 1 */
float fr2, fg2, fb2; /* Floating point RGB values of color 2 */
int ir, ig, ib; /* Integer RGB values after combing the two above */
int col1, col2;
unsigned char bestcolor; /* Best match */
lightlevel1 = (float)frame / (float)maxframe;
/* Calculate the percentage of color 1 */
lightlevel2 = 1.0 - lightlevel1;
/* Percentage of color 2 is the 100% - lightlevel1 */
for (col2 = 0; col2 < MAXCOL; col2++)
for (col1 = 0; col1 < MAXCOL; col1++)
{
fr = (float)pal[col1].r * lightlevel1;
fg = (float)pal[col1].g * lightlevel1;
fb = (float)pal[col1].b * lightlevel1;
fr2= (float)pal[col2].r * lightlevel2;
fg2= (float)pal[col2].g * lightlevel2;
fb2= (float)pal[col2].b * lightlevel2;
/* Calculate the two new colors */
ir = (fr + fr2);
ig = (fg + fg2);
ib = (fb + fb2);
/* Combine the percentage of color 1 with the percentage of color 2
to form a new color */
bestcolor = closest_match (ir, ig, ib, pal);
fadetable[frame * (MAXCOL*MAXCOL) + col2 * MAXCOL + col1] = bestcolor;
}
}
#define NUMFRAMES 10
static void InitPalette(CTabHandle ctab)
{
WORD ptr, i;
RGBColor color;
UBYTE *fadetable;
fadetable = new UBYTE[MAXCOL * MAXCOL * (NUMFRAMES / 2)];
for (i = 0; i < NUMFRAMES/2; i++)
{
create_fade_table (i, NUMFRAMES, fadetable, pal);
}
for(i=0; i<256; i++)
{
color.red = pal[i].r * 256L;
color.green = pal[i].g * 256L;
color.blue = pal[i].b * 256L;
(*ctab)->ctTable[i].rgb = color;
}
SetEntries(0, 255, (*ctab)->ctTable);
}
#define kAmbient 0.3
static void MakePalette(CTabHandle ctab)
{
short i, j, specular, diffuse, pal_index;
RGBColor col, color, background;
color.red = 65535;
color.green = 0;
color.blue = 0;
col.red = color.red * kAmbient;
col.green = color.green * kAmbient;
col.blue = color.blue * kAmbient;
pal_index = 0;
for(j=0; j<kDiffuse; j++)
{
col.red += (color.red - col.red) / (kDiffuse-j);
col.green += (color.green - col.green) / (kDiffuse-j);
col.blue += (color.blue - col.blue) / (kDiffuse-j);
(*ctab)->ctTable[pal_index++].rgb = col;
}
color.red = 0xFFFF;
color.green = 0xFFFF;
color.blue = 0xFFFF;
for(j=0; j<kSpecular; j++)
{
col.red += (color.red - col.red) / (kSpecular-j);
col.green += (color.green - col.green) / (kSpecular-j);
col.blue += (color.blue - col.blue) / (kSpecular-j);
(*ctab)->ctTable[pal_index++].rgb = col;
}
SetEntries(0, 254, (*ctab)->ctTable);
}
void main(void)
{
char str[255];
LONG TickStart, FrameCount;
InitToolBox();
load_pic();
object3d object;
object.importV3D("text.v3d");
WindowPtr window;
GWorldPtr gWorld;
OSErr iErr;
CGrafPtr savePort;
GDHandle saveGDev;
PixMapHandle pixBase;
GDHandle iMainScreen;
PixMapPtr iPixMap;
window = ::GetNewCWindow(128, NULL, (WindowPtr) -1);
::ShowWindow(window);
::SetPort(window);
iMainScreen = GetMainDevice();
iPixMap = *((**iMainScreen).gdPMap);
MakePalette(iPixMap->pmTable);
rBounds = window->portRect;
::OffsetRect(&rBounds, -rBounds.left, -rBounds.top);
::SetPt(&middle, rBounds.right >> 1, rBounds.bottom >> 1);
iErr = ::NewGWorld(&gWorld, 8, &rBounds, iPixMap->pmTable, NULL, keepLocal);
if (iErr != noErr)
{
::DisposeWindow(window);
return;
}
pixBase = ::GetGWorldPixMap(gWorld);
::LockPixels(pixBase);
::HLockHi((Handle) pixBase);
baseAddr = (**pixBase).baseAddr;
rowBytes = (**pixBase).rowBytes & 0x1FFF;
::BackColor( whiteColor );
::ForeColor( blackColor );
::GetGWorld(&savePort, &saveGDev);
::SetGWorld(gWorld, NULL);
::BackColor(blackColor);
::ForeColor(whiteColor);
::SetGWorld(savePort, saveGDev);
EventRecord event;
BOOL quit = FALSE;
#ifdef use_profiler
if (::ProfilerInit(collectDetailed, bestTimeBase, 100, 10) != noErr)
::ExitToShell();
#endif
TickStart = ::TickCount();
FrameCount = 0;
object.applyTexture();
object.makeRotMatrix(0, 0, 0);
object.setGNormals();
object.localRotate();
Point curPt, oldPt;
LONG diffPt;
BOOL down;
::GetMouse(&curPt);
oldPt = curPt;
while (!quit)
{
GetMouse(&curPt);
if (PtInRect(curPt, &window->portRect)) {
if (::StillDown())
{
::SetCursor(*GetCursor(iNewHandCursor));
down = TRUE;
} else
{
::SetCursor(*GetCursor(iHandCursor));
down = FALSE;
}
} else
::SetCursor(&qd.arrow);
::SetGWorld(gWorld, NULL);
::EraseRect(&rBounds);
if (!::EqualPt(curPt, oldPt) && down)
{
if (event.modifiers & optionKey)
{
camera.view.z += (curPt.v - oldPt.v) * 100;
object.localRotate();
} else
{
object.makeRotMatrix(down ? curPt.v - oldPt.v : 0,
down ? curPt.h - oldPt.h : 0, 0);
object.setGNormals();
object.localRotate();
}
oldPt = curPt;
}
object.display();
::sprintf(str, "fps: %.2f", (FrameCount * 60.0) / (::TickCount() - TickStart));
::MoveTo(10, 20);
::DrawText(str, 0, strlen(str));
::SetGWorld(savePort, saveGDev);
::CopyBits(*(BitMap**) gWorld->portPixMap, *(BitMap**) savePort->portPixMap,
&rBounds, &rBounds, srcCopy, NULL);
if (::WaitNextEvent(everyEvent, &event, 0, NULL))
{
if (event.what == mouseDown)
{
WindowPtr theWindow;
short iWinPart;
iWinPart = ::FindWindow(event.where, &theWindow);
switch (iWinPart)
{
case inGoAway:
if (::TrackGoAway(theWindow, event.where))
quit = TRUE;
break;
case inContent:
oldPt = curPt;
break;
}
}
}
FrameCount++;
}
#ifdef use_profiler
::ProfilerDump("\pProfilerIntro.profiler");
::ProfilerTerm();
#endif
::FlushEvents(everyEvent, 0);
delete_pic();
::DisposeGWorld(gWorld);
::DisposeWindow(window);
}